package ru.mirent;

import io.qameta.allure.attachment.DefaultAttachmentProcessor;
import io.qameta.allure.attachment.FreemarkerAttachmentRenderer;
import io.qameta.allure.jsonunit.DiffAttachment;
import io.qameta.allure.jsonunit.DiffModel;
import io.qameta.allure.jsonunit.JsonPatchMatcher;
import net.javacrumbs.jsonunit.core.Option;
import net.javacrumbs.jsonunit.core.internal.Options;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * Демонстрация работы библиотеки 'allure-jsonunit'.
 * Библиотека позволяет сравнивать ва JSON файла и формировать в Allure-отчете вывод с различиями в сравнении.
 * Для вывода различий используется шаблон библиотеки Freemarker.
 */
class JsonUnitForDiffJsonTest {
    private final String expected = "{\"key1\":\"значение 1\",\"key5\":\"value3\"}";
    private final String actual = "{\"key1\":\"значение 2\",\"key2\":\"value2\",\"key3\":\"value3\",\"key4\":\"value3\"}";

    /**
     * Демонстрация проверки двух JSON структур с отображением разницы в Allure-отчете.
     * В данном примере используется обновленынй файл из проект по пути '/tpl/diff.ftl', который переопределят
     * аналогичный файл по такому же пути из самой библиотеки. Переопределение проиходит по принципу очередности чтения
     * файлов, сначала проект и если в нем нет нужного файла, то поиск происходит в classpath.
     */
    @Test
    void shouldDiffWithIgnoringPaths() {
        boolean result = JsonPatchMatcher.jsonEquals(expected)
                .whenIgnoringPaths("key2")
                .matches(actual);

        // Ожидается что будет отброшено исключение и тем самым будет создано
        // вложение с разницей между двумя сравниваемы JSON
        Assertions.assertThrows(org.opentest4j.AssertionFailedError.class,
                () -> Assertions.assertTrue(result)
        );
    }

    /**
     * Содержимое метода {@link #shouldDiffWithIgnoringPaths()} в части формирования вложения из шаблона Freemarker.
     * Вариант с шаблоном Freemarker как альтернатива формированию HTML-кода.
     * В данном примере используется обновленынй файл из проект по пути '/tpl/diff.ftl', который переопределят
     * аналогичный файл по такому же пути из самой библиотеки
     */
    @Test
    void innerShouldDiffWithIgnoringPathsTest() {
        // Значение параметра path взято из теста shouldDiffWithIgnoringPaths()
        String path = "{\"key1\":[\"value11\",\"value1\"],\"key5\":[\"value3\",0,0],\"key3\":[\"value3\"],\"key4\":[\"value3\"]}";

        DiffModel diffModel = new DiffModel(actual, expected, path);
        DiffAttachment diffAttachment = new DiffAttachment(diffModel);

        // Файл 'diff.ftl' расположен в зависимости io.qameta.allure:allure-jsonunit в папке '/tpl/'
        // Если файл с аналогичным именем поместить в текущий проект по пути '/tpl/diff.ftl', то будет использовать он,
        // т.к. загрузка даного файла осуществляется из ClassPath.
        (new DefaultAttachmentProcessor()).addAttachment(diffAttachment,
                new FreemarkerAttachmentRenderer("diff.ftl"));
    }

    /**
     * Содержимое метода {@link #shouldDiffWithIgnoringPaths()} в части формирования вложения из шаблона Freemarker.
     * Вариант с шаблоном Freemarker как альтернатива формированию HTML-кода.
     */
    @Test
    void exampleCustomTemplateDiffTest() {
        // Значение параметра path взято из теста shouldDiffWithIgnoringPaths()
        String path = "{\"key1\":[\"value11\",\"value1\"],\"key5\":[\"value3\",0,0],\"key3\":[\"value3\"],\"key4\":[\"value3\"]}";

        DiffModel diffModel = new DiffModel(actual, expected, path);
        DiffAttachment diffAttachment = new DiffAttachment(diffModel);

        // Файл 'diff.ftl' расположен в зависимости io.qameta.allure:allure-jsonunit в папке '/tpl/'
        (new DefaultAttachmentProcessor()).addAttachment(diffAttachment,
                new FreemarkerAttachmentRenderer("custom-diff.ftl"));
    }

    /**
     * Генерация вложения с шаблоном сравнения 'custom-diff.ftl'.
     */
    @Test
    void exampleCustomJsonPatchMatcherTest() {
        boolean result = CustomJsonPatchMatcher.jsonEquals(expected)
                .whenIgnoringPaths("key2")
                .matches(actual);

        // Ожидается что будет отброшено исключение и тем самым будет создано
        // вложение с разницей между двумя сравниваемы JSON
        Assertions.assertThrows(org.opentest4j.AssertionFailedError.class,
                () -> Assertions.assertTrue(result)
        );
    }

    @Test
    void shouldMatchWithOptions() {
        final boolean result = JsonPatchMatcher.jsonEquals("[1,2]")
                .withOptions(Options.empty().with(Option.IGNORING_ARRAY_ORDER))
                .matches("[2,1]");
        Assertions.assertTrue(result);
    }

    @Test
    void shouldMatchWhenOptions() {
        final boolean result = JsonPatchMatcher.jsonEquals("[1,2]")
                .when(Option.IGNORING_ARRAY_ORDER).matches("[2,1]");
        Assertions.assertTrue(result);
    }
}
